package com.mantou.cdl.net;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.entity.GzipDecompressingEntity;

import com.gargoylesoftware.htmlunit.CookieManager;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.mantou.proxyservice.utils.NullUtil;


public class  HttpInvoker {

	private String url;
	private static   CookieManager cookieManager = new CookieManager();
	private boolean cookieenable = false;
	private boolean proxyenable =false;
	private boolean relocationnable = false;
	private String proxyip;
	private int proxyport;

	//test
	public HttpInvoker setproxy(String ip,int port){
		proxyip = ip;
		proxyport = port;
		proxyenable = true;
		return this;
	}

	public boolean isCookieenable() {
		return cookieenable;
	}

	public void setCookieenable(boolean cookieenable) {
		this.cookieenable = cookieenable;
	}

	public boolean isProxyenable() {
		return proxyenable;
	}

	public void setProxyenable(boolean proxyenable) {
		this.proxyenable = proxyenable;
	}

	public boolean isRelocationnable() {
		return relocationnable;
	}

	public void setRelocationnable(boolean relocationnable) {
		this.relocationnable = relocationnable;
	}

	/**
	 * �?��请求的URL，有可能有重定向。重定向后的url和原来的url就不�?���?
	 */
	private String lastUrl ;
	public HttpInvoker(String url){
		this.url = url;
	}

	public HttpResult requestFromHtmlUnit(HtmlUnitResultWait waitHandler){

		WebClient webClient = new WebClient();

		webClient.getOptions().setThrowExceptionOnScriptError(false);  
		webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);   
		webClient.getOptions().setJavaScriptEnabled(true);  
		webClient.getOptions().setActiveXNative(false);  
		webClient.getOptions().setCssEnabled(false);  
		webClient.setAjaxController(new NicelyResynchronizingAjaxController()); 

		//cookie

		try {
			if(cookieenable){
				Set<com.gargoylesoftware.htmlunit.util.Cookie> cookies = cookieManager.getCookies(new URL(url));
				com.gargoylesoftware.htmlunit.CookieManager destCookieManager = webClient.getCookieManager();

				Iterator<com.gargoylesoftware.htmlunit.util.Cookie>  it =cookies.iterator();
				while(it.hasNext()){
					com.gargoylesoftware.htmlunit.util.Cookie itemCookie = it.next();
					//itemCookie.
					destCookieManager.addCookie(itemCookie);
				}
			}

			HtmlPage page = webClient
					.getPage(url);
			if(waitHandler != null){
				long timeOut = waitHandler.getTimeOut();
				long interverl = timeOut/100;
				if(interverl <20)
					interverl = 20;

				long times =timeOut/interverl;
				if(times < 1)
					times =1;

				long testTime =0;

				while(testTime<times){
					if(waitHandler.canReturn(page.asXml(), page.getUrl().toString())){

						if(cookieenable){
							Set<com.gargoylesoftware.htmlunit.util.Cookie> fromCookies= webClient.getCookieManager().getCookies();
							Iterator<com.gargoylesoftware.htmlunit.util.Cookie> fromit = fromCookies.iterator();

							while(fromit.hasNext()){
								cookieManager.addCookie(fromit.next());
							}
						}
						return  new HttpResult(200,null,page.asXml().getBytes());
					}
					testTime ++;
					Thread.sleep(interverl);
				}
			}
			lastUrl =page.getUrl().toString();
			//cookie
			return  new HttpResult(200,null,page.asXml().getBytes());
		} catch (FailingHttpStatusCodeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			webClient.closeAllWindows();
		}

		return new HttpResult(-1,null,null);
	}
	public HttpResult postFromHtmlUnit(HtmlUnitResultWait waitHandler,List<NameValuePair> nvps,String orign,String referer,List<NameValuePair> headers){
		try {
			WebClient webClient = new WebClient();

			webClient.getOptions().setThrowExceptionOnScriptError(false);  
			webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);   
			webClient.getOptions().setJavaScriptEnabled(true);  
			webClient.getOptions().setActiveXNative(false);  
			webClient.getOptions().setCssEnabled(false);  
			webClient.setAjaxController(new NicelyResynchronizingAjaxController()); 

			if(cookieenable){
				Set<com.gargoylesoftware.htmlunit.util.Cookie> cookies = cookieManager.getCookies(new URL(url));
				com.gargoylesoftware.htmlunit.CookieManager destCookieManager = webClient.getCookieManager();

				Iterator<com.gargoylesoftware.htmlunit.util.Cookie>  it =cookies.iterator();
				while(it.hasNext()){
					com.gargoylesoftware.htmlunit.util.Cookie itemCookie = it.next();
					//itemCookie.
					destCookieManager.addCookie(itemCookie);
				}
			}

			WebRequest webRequest = new WebRequest(new URL(url), com.gargoylesoftware.htmlunit.HttpMethod.POST);
			if(headers != null){
				for(NameValuePair head:headers){
					webRequest.setAdditionalHeader(head.getName(), head.getValue());
				}
			}
			//((HttpPost)webRequest.getHttpMethod()).


			webClient.loadWebResponse(webRequest);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}

	private void setHeader(HttpMethod method,String orign,String referer){
		method.getParams().setParameter(HttpMethodParams.SINGLE_COOKIE_HEADER,true);
		method.addRequestHeader("Connection", "keep-alive");
		method.addRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		method.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36");
		//getMethod.addRequestHeader("Accept-Encoding", "gzip,deflate");
		method.addRequestHeader("Accept-Language", "zh-CN,zh;q=0.8");
		if(!NullUtil.isNull(orign))
			method.addRequestHeader("Origin", orign);
		if(!NullUtil.isNull(referer))
			method.addRequestHeader("Referer", referer);
	}

	public HttpResult post(List<NameValuePair> nvps,String orign,String referer,List<NameValuePair> headers){
		try {
			HttpClient httpClient = new HttpClient();
			PostMethod post = new PostMethod(url);


			setHeader(post,orign,referer);

			if(headers != null){
				for(NameValuePair nameValuepair:headers){
					post.addRequestHeader(nameValuepair.getName(), nameValuepair.getValue());
				}

			}

			post.setRequestBody(nvps.toArray(new NameValuePair[nvps.size()]));

			if(cookieenable){

				httpClient.getState().addCookies(toHttpClient(cookieManager.getCookies(new URL(url))));
			}
			int statusCode = httpClient.executeMethod(post);
			if(cookieenable){
				Cookie[] cookies=httpClient.getState().getCookies();
				for(Cookie cookie:cookies){
					cookieManager.addCookie(new com.gargoylesoftware.htmlunit.util.Cookie(cookie.getDomain(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getExpiryDate(), cookie.getSecure(), false));
				}
			}
			if(statusCode == 200){
				return new HttpResult(statusCode,post.getResponseBody());
			}else if(statusCode == 302){
				Header header = post.getResponseHeader("Location");
				String location = null;
				if(header != null){
					location = header.getValue();
				}
				return new HttpResult(statusCode,location,post.getResponseBody());
			}else{
				System.out.println("status Code:"+statusCode);
				return new HttpResult(statusCode);
			}

		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (HttpException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public HttpResult request() throws HttpException, IOException{
		/* 1.生成 HttpClinet 对象并设置参�?*/
		HttpClient httpClient = new HttpClient();
		httpClient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
		GetMethod getMethod = new GetMethod(url);
		if(!relocationnable)
			getMethod.setFollowRedirects(false);  
		try{
			if(proxyenable){
				httpClient.getHostConfiguration().setProxy(proxyip, proxyport);
			}
			//设置 Http 连接超时 5s
			httpClient.getHttpConnectionManager().getParams()
			//							.setConnectionTimeout(getTimeOut());
			.setConnectionTimeout(100000);
			httpClient.getHttpConnectionManager().getParams().setSoTimeout(100000);

			// 设置 get请求超时
			getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 10000);
			// 设置请求重试处理
			getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
					new DefaultHttpMethodRetryHandler());
			//设置UA
			setHeader(getMethod,null,null);

			if(cookieenable){
				httpClient.getState().addCookies(toHttpClient(cookieManager.getCookies(new URL(url))));
			}

			int statusCode = httpClient.executeMethod(getMethod);

			lastUrl = getMethod.getURI().toString();

			if(cookieenable){
				/*
				 * cookie 获取 处理
				 */
				Cookie[] cookies=httpClient.getState().getCookies();
				for(Cookie cookie:cookies){
					cookieManager.addCookie(new com.gargoylesoftware.htmlunit.util.Cookie(cookie.getDomain(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getExpiryDate(), cookie.getSecure(), false));
					//System.out.println("after request "+"   "+cookie.getDomain()+"  "+cookie.getName()+" "+cookie.getPath()+"  "+cookie.getValue()+"  "+cookie.getExpiryDate());
				}
			}
			if(statusCode == 200){
				Header content_encoding = getMethod.getResponseHeader("Content-Encoding");
				if(content_encoding != null && content_encoding.getValue().toLowerCase().indexOf("gzip")>-1){
					ByteArrayOutputStream out = new ByteArrayOutputStream();
					ByteArrayInputStream in = new ByteArrayInputStream(getMethod.getResponseBody());
					GZIPInputStream gunzip = new GZIPInputStream(in);
					byte[] buffer = new byte[256];
					int n;
					while ((n = gunzip.read(buffer)) >= 0) {
						out.write(buffer, 0, n);
					}
					return new HttpResult(statusCode,out.toByteArray());
				}
				return new HttpResult(statusCode,getMethod.getResponseBody());
			}else if(statusCode == 302){
				Header header = getMethod.getResponseHeader("Location");
				String location = null;
				if(header != null){
					location = header.getValue();
				}
				return new HttpResult(statusCode,location,getMethod.getResponseBody());
			}else{
				System.out.println("status Code:"+statusCode);
				return new HttpResult(statusCode);
			}
		}finally{
			getMethod.releaseConnection();
		}

	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getLastUrl() {
		return lastUrl;
	}

	public void setLastUrl(String lastUrl) {
		this.lastUrl = lastUrl;
	}
	/**
	 * Converts this cookie to an HttpClient cookie.
	 * @return an HttpClient version of this cookie
	 */
	public static org.apache.commons.httpclient.Cookie toHttpClient(com.gargoylesoftware.htmlunit.util.Cookie inCookie) {
		final org.apache.commons.httpclient.Cookie cookie =
				new org.apache.commons.httpclient.Cookie(inCookie.getDomain(),inCookie.getName(),inCookie.getValue(),inCookie.getPath(),inCookie.getExpires(),inCookie.isSecure());
		return cookie;
	}

	/**
	 * Converts the specified collection of cookies into an array of HttpClient cookies.
	 * @param cookies the cookies to be converted
	 * @return the specified cookies, as HttpClient cookies
	 */
	public static org.apache.commons.httpclient.Cookie[] toHttpClient(final Collection<com.gargoylesoftware.htmlunit.util.Cookie> cookies) {
		final org.apache.commons.httpclient.Cookie[] array = new org.apache.commons.httpclient.Cookie[cookies.size()];
		final Iterator<com.gargoylesoftware.htmlunit.util.Cookie> it = cookies.iterator();
		for (int i = 0; i < cookies.size(); i++) {
			array[i] = toHttpClient(it.next());
		}
		return array;
	}
}
